package midi;

import javax.sound.midi.*;
import javax.sound.midi.Sequencer.SyncMode;

public class SequencerSynchronizer {
	private static Sequencer masterSeq;
	private static final SyncMode syncMode = SyncMode.MIDI_SYNC;
	
	public SequencerSynchronizer(float tempoInBPM, float tempoFactor, 
			Receiver syncedRec, float divisionType, int resolution,
			int syncChannel, int syncControllerNumber)
	throws MidiUnavailableException, InvalidMidiDataException{
		masterSeq = MidiSystem.getSequencer(false);
		masterSeq.setTempoInBPM(tempoInBPM);
		masterSeq.setTempoFactor(tempoFactor);
		masterSeq.setMasterSyncMode(syncMode);
		masterSeq.open();
		
		masterSeq.getTransmitter().setReceiver(syncedRec);
		masterSeq.setLoopEndPoint(0);
		masterSeq.setLoopStartPoint(0);
		masterSeq.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
		
		masterSeq.setSequence(SyncSequence(divisionType, resolution, syncChannel, syncControllerNumber));
		
		masterSeq.start();
	}	
	
	public static Sequencer getSynchronizedSequencer() throws MidiUnavailableException, NullPointerException
	{
			Sequencer syncSeq = MidiSystem.getSequencer(false);
			syncSeq.setTempoInBPM(masterSeq.getTempoInBPM());
			syncSeq.setTempoFactor(masterSeq.getTempoFactor());
			syncSeq.setSlaveSyncMode(syncMode);
		
			return syncSeq;
	}
	
	public static Sequence SyncSequence(float divisionType, int resolution, int syncChannel, int syncControllerNumber)
			throws InvalidMidiDataException
	{
		Sequence syncSeq = new Sequence(divisionType, resolution);
		Track track = syncSeq.createTrack();
		
		ShortMessage msg = new ShortMessage();
		msg.setMessage(ShortMessage.CONTROL_CHANGE, syncChannel, syncControllerNumber, 127);
		
		track.add(new MidiEvent(msg, 1));
		
		return syncSeq;
		
	}
}
